/*
 * 代表一个待爬的一类页面，从这一类页面爬出的数据成为“数据表”，
 * 每一页的数据成为“数据行”或“一行数据”
 */
var SourcePage = function(db){
	this.fields = []; //数据表结构（即字段，不包括连接页面的字段）
	this.linkedPages = []; //连接页面，比如“详情页面”
	if(db){
		this.id = db.id;
		this.name = db.name;
		this.url = db.url; //页面的URL或能获取URL的选择器
		this.rowElement = new PapaElement(db.rowElement); //数据行的元素或选择器
		this.paging = new Paging(db.paging); //翻页策略
		for (var i = 0; i < db.fields.length; i++) {
			this.fields.push(new PapaField(db.fields[i]));
		}
		for (var i = 0; i < db.linkedPages.length; i++) {
			this.linkedPages.push(new LinkedPage(db.linkedPages[i]));
		}
	}
	
	this.toDB = function(){
		var db_s = {
			id: this.id,
			name: this.name,
			url: this.url,
			rowElement: this.rowElement.toDB()
		}
		if(this.paging){
			db_s.paging = this.paging.toDB();
		}
		db_s.fields = [];
		for (var i = 0; i < this.fields.length; i++) {
			db_s.fields.push(this.fields[i].toDB());
		}
		
		db_s.linkedPages = [];
		for (var i = 0; i < this.linkedPages.length; i++) {
			db_s.linkedPages.push(this.linkedPages[i].toDB());
		}
		return db_s;
	}
}

/*
 * 内容提取器。
 * 根据选择器提取文本（text），属性（attr），或者自定义方法（method）从元素（Element）中提取相关的信息
 */
var ContentExtractor = function(db){
	if(db){
		this.type = db.type;
		this.attr = db.attr;
		this.method = db.method; //找到元素后的处理
		this.process = db.process; //拿到提取的内容后的处理
	}
	
	this.getValue = function(ele){
		var r = null;
		if(this.method){
			var m = eval("(function _$_$(){ return ("+ this.method +")})");
			r = m.call(ele[0]);
		}
		else if(this.type == 'attr'){
			r = ele.attr(this.attr);
		}
		else{
			r = ele.text();
		}
		if(this.process){
			var m = eval("(function _$_$(){ return ("+ this.process +")})");
			r = m.call(r);
		}
		return r;
	}
	this.toString = function(){
		if(this.type == 'text'){
			return '文本';
		}
		if(this.type == 'method'){
			return this.method;
		}
		if(this.type == 'attr'){
			return '属性:' + this.attr;
		}
	}
	this.toDB = function(){
		return {
			type: this.type,
			attr: this.attr,
			method: this.method,
			process: this.process
		}
	}
}

ContentExtractor.types = ['text', 'attr', 'method'];

var PapaElement = function(db){
	this.elements = null; //jquery element
	if(db){
		this.name = db.name;
		this.selector = db.selector; //String
		this.contentExtractor = db.contentExtractor ? 
				new ContentExtractor(db.ContentExtractor) : null;
		if(papaElements.length && typeof db.parentElement == 'string'){
			var index = parseInt(db.parentElement.substring(1));
			this.parentElement = papaElements[index];
		}else{
			this.parentElement = db.parentElement; //PapaElement
		}
	}
	
	//topParent 元素选择器的顶层元素，比如每个字段元素的顶层元素是行元素
	this.select = function(topParent){
		if(topParent || !this.elements){
			if(this.parentElement){
				this.elements = this.parentElement.select(topParent).find(this.selector);
			}else{
				this.elements = topParent ? 
						topParent.select().find(this.selector) : $(this.selector);
			}
		}
		return this.elements;
	}
	
	this.getValue = function(extractor, topParent){
		if(extractor){
			return extractor.getValue(this.select(topParent));
		}
		return this.contentExtractor.getValue(this.select(topParent));
	}
	
	this.toString = function(){
		var a = [];
		var ele = this;
		while(true){
			a.push(ele.selector);
			ele = ele.parentElement;
			if(!ele){
				break;
			}
		}
		return a.reverse().join(' ');
	}
	
	this.toDB = function(){
		var db_s = {
			name: this.name,
			selector: this.selector
		};
		if(this.parentElement){
			//papaElements是全局变量 
			db_s.parentElement = '$' + papaElements.indexOf(this.parentElement);
		}
		var ce = this.contentExtractor;
		if(ce){
			db_s.contentExtractor = ce.toDB();
		}
		return db_s;
	}
}

/*
 * 分页策略
 * 1）根据分页链接中的URL分页
 * 2）下拉滚动条加载分批数据（Ajax）
 * 3）Click事件分页（Ajax）
 */
var Paging = function(db){
	if(db){
		this.type = db.type;
		this.nextPageElement = new PapaElement(db.nextPageElement); 
	}
	
	this.nextPage = function(topElement){
		var ele = this.nextPageElement.select(topElement);
		if(this.type == 'url'){
			return ele[0].href;
		}
		else if(this.type == 'scroll'){
			var height = ele.height();
			var top = 200;
			while(true){
				if(top < height){
					ele.scrollTop(top);
					top += 200;
				}else{
					ele.scrollTop(height);
					break;
				}
			}
		}
		else if(this.type == 'click'){
			ele.click();
		}
	}
	
	this.toDB = function(){
		return {
			type: this.type,
			nextPageElement: this.nextPageElement && this.nextPageElement.toDB()
		}
	}
}
Paging.types = ['url', 'scroll', 'click'];

var PapaField = function(db){
	if(db){
		this.id = db.id;
		this.title = db.title;
		this.element = new PapaElement(db.element);
		this.unique = db.unique;
		this.contentExtractor = db.contentExtractor ? 
				new ContentExtractor(db.contentExtractor) : null;
	}else{
		this.unique = false;
	}
	
	this.getValue = function(rowElement){
		return this.element.getValue(this.contentExtractor, rowElement);
	}
	
	this.toDB = function(){
		var db_f = {
			id: this.id,
			title: this.title,
			unique: this.unique,
			element: this.element.toDB()
		}
		var ce = this.contentExtractor;
		if(ce){
			db_f.contentExtractor = ce.toDB();
		}
		return db_f;
	}
}

var LinkedPage = function(db){
	if(db){
		this.one2many = db.one2many; //主页和链接页的关系是否一对多，默认false
		this.paging = new Paging(db.paging);
		this.sourcePage = db.sourcePage;
	}
	
	this.toDB = function(){
		return {
			id: this.id,
			one2many: this.one2many,
			paging: this.paging.toDB(),
			//sourcePages是全局变量 
			sourcePage: '$' + sourcePages.indexOf(this.sourcePage)
		}
	}
}

var sitemap2db = function(){
	var db = {};
	//PapaElement
	var sel = sitemap.selectors || [];
	var db_sel = [];
	for (var i = 0; i < sel.length; i++) {
		var s = sel[i];
		db_sel.push(s.toDB());
	}
	db.selectors = db_sel;
	
	//SourcePage
	var sps = sitemap.pages || [];
	var db_sps = [];
	for (var i = 0; i < sps.length; i++) {
		var s = sps[i];
		db_sps.push(s.toDB());
	}
	db.pages = db_sps;
	return db;
}


var papaElements, sourcePages, sitemap;
var initSitemap = function(){
	papaElements = [];
	sourcePages = [];
	sitemap = {
		selectors: papaElements,
		pages: sourcePages
	}
}

var db2sitemap = function(db){
	initSitemap();
	//Selector
	var db_sel = db.selectors || [];
	for (var i = 0; i < db_sel.length; i++) {
		papaElements.push(new PapaElement(db_sel[i]));
	}
	//link
	for (var i = 0; i < papaElements.length; i++) {
		var e = papaElements[i];
		if(typeof e.parentElement == 'string'){
			var index = parseInt(e.parentElement.substring(1));
			e.parentElement = papaElements[index];
		}
	}
	
	//SourcePage
	var db_sps = db.pages || [];
	for (var i = 0; i < db_sps.length; i++) {
		sourcePages.push(new SourcePage(db_sps[i]));
	}
	//link
	for (var i = 0; i < sourcePages.length; i++) {
		for (var j = 0; j < sourcePages[i].linkedPages.length; j++) {
			var lp = sourcePages[i].linkedPages[j];
			if(typeof lp.sourcePage == 'string'){
				var index = parseInt(lp.sourcePage.substring(1));
				lp.sourcePage = sourcePages[index];
			}
		}
	}
}